package org.slusk.thynwor.util;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import org.slusk.thynwor.neat.ActivatableNetFactory;

import com.anji.hyperneat.nd.ActivatorND;
import com.anji.hyperneat.nd.NDActivatorArray;
import com.anji.hyperneat.nd.NDActivatorArray.ActivatorArrayIterator;
import com.anji.hyperneat.nd.NDFloatArray;
import com.anji.hyperneat.onlinereinforcement.GridNetHebbianABC;
import com.anji.hyperneat.onlinereinforcement.GridNetNDLR;
import com.anji.hyperneat.onlinereinforcement.GridNetTD;
import com.anji.hyperneat.onlinereinforcement.IOnlineLearningActivatorND;
import com.anji.util.Properties;

public class SubstrateDump {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
	   	Properties props = new Properties();
        props.loadFromResources(args);

		NDActivatorArray sasasNetArray = ActivatableNetFactory.createGridNets(props);	
		String filePath = props.getProperty("SubstrateDump.outputFile", null);
		if (null == filePath) print(getString(sasasNetArray));
		else dumpToFile(filePath, getString(sasasNetArray));
	}

	public static String getString(NDActivatorArray sasasNetArray) {
		StringBuilder sb = new StringBuilder();
		for (ActivatorArrayIterator it = sasasNetArray.iterator(); it.hasNext(); it.next()) {
			ActivatorND activator = it.get();
			ActivatorND net = it.get();
			int[] coords = it.getCurrentCoordinates();
			sb.append("Net " + coords[0]);
			for (int i = 1; i < coords.length; i++) sb.append(", "+coords[i]);
			sb.append("\n");
			
			if (activator instanceof IOnlineLearningActivatorND) {
				sb.append("Reinforcement Learning Net Type: " + activator.getClass() +"\n");
				net = ((IOnlineLearningActivatorND)activator).getWorkingActivator();
			}
			sb.append("Type: "+net.getClass() + "\n");
			sb.append("Connections:" + "\n");
			NDFloatArray[] allConnections = net.getWeights();
			int set = 0;
			for (NDFloatArray connections : allConnections) {
				sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
				sb.append(connections.toString() + "\n");
			}
			
			sb.append("Bias:" + "\n");
			NDFloatArray[] allBias = net.getBias();
			set = 1;
			for (NDFloatArray bias : allBias) {
				sb.append("Layer " + set++ +  ":" + "\n");
				sb.append(bias.toString() + "\n");
			}
			
			if (activator instanceof IOnlineLearningActivatorND) {
				net = ((IOnlineLearningActivatorND) activator).getWorkingActivator();
				if (net instanceof GridNetNDLR) {
					sb.append("Learning Rates:" + "\n");
					GridNetNDLR n = (GridNetNDLR) net;
					set = 0;
					for (NDFloatArray learningRates : n.getWeightLearningRates()) {
						sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
						sb.append(learningRates.toString() + "\n");
					}
					
					sb.append("Bias Learning Rates:" + "\n");
					set = 0;
					for (NDFloatArray learningRates : n.getBiasLearningRates()) {
						sb.append("Layer " + set++ + "\n");
						sb.append(learningRates.toString() + "\n");
					}
				} else if (net instanceof GridNetHebbianABC) {
					GridNetHebbianABC n = (GridNetHebbianABC) net;
					sb.append("Learning Rate A:" + "\n");
					set = 0;
					for (NDFloatArray learningRates : n.getALearningRates()) {
						sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
						sb.append(learningRates.toString() + "\n");
					}
					
					sb.append("Learning Rate B:" + "\n");
					set = 0;
					for (NDFloatArray learningRates : n.getBLearningRates()) {
						sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
						sb.append(learningRates.toString() + "\n");
					}
					
					sb.append("Learning Rate C:" + "\n");
					set = 0;
					for (NDFloatArray learningRates : n.getCLearningRates()) {
						sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
						sb.append(learningRates.toString() + "\n");
					}
					
					sb.append("Learning Rate n:" + "\n");
					set = 0;
					for (NDFloatArray learningRates : n.getNLearningRates()) {
						sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
						sb.append(learningRates.toString() + "\n");
					}
				} else if (net instanceof GridNetTD) {
					GridNetTD n = (GridNetTD) net;
					sb.append("Learning Rate Alphas:" + "\n");
					set = 0;
					for (NDFloatArray learningRates : n.getAlphas()) {
						sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
						sb.append(learningRates.toString() + "\n");
					}
					
					sb.append("Lambdas:" + "\n");
					set = 0;
					for (NDFloatArray learningRates : n.getLambdas()) {
						sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
						sb.append(learningRates.toString() + "\n");
					}
					
					sb.append("Gammas:" + "\n");
					set = 0;
					for (NDFloatArray learningRates : n.getGammas()) {
						sb.append("Layer " +set+ "-" + (++set) + ":" + "\n");
						sb.append(learningRates.toString() + "\n");
					}
				}				
				
			}
			
			sb.append("\n");
		}
		return sb.toString();
	}

	public static void dumpToFile(String filePath, String data) throws IOException {
		BufferedWriter out = new BufferedWriter(new FileWriter(filePath));
		
		out.write(data);
		
		out.close();
	}	
	
	private static void print(String msg) {System.out.print(msg);}
	private static void println(String msg) {System.out.println(msg);}
}
